package org.threebitsoftware.tbb.dao.bridge;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import org.apache.log4j.Logger;
import org.threebitsoftware.dao.generated.Phonenumber;
import org.threebitsoftware.dao.generated.PhonenumberKey;
import org.threebitsoftware.dao.generated.dao.PhonenumberDAO;
import org.threebitsoftware.dao.generated.orm.PhonenumberDAOImpl;
import org.threebitsoftware.tbb.dao.Contact;
import org.threebitsoftware.tbb.dao.DaoHelper;
import org.threebitsoftware.tbb.dao.PhoneNumber;

import com.pew.util.dao.DatabaseConection;
import com.pew.util.dao.DatabaseUtil;

/*
 * Created: Nov 14, 2009
 * Original Author: Elwin
 * Project:
 * Copyright:
 * 
 * Purpose:
 */

/*
 * Copyright (c) 2009, 3BitSoftware
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   * Neither the name of the <organization> nor the
 *     names of its contributors may be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY <copyright holder> ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

public class PhoneNumberBridge {
	private static Logger cLogger = Logger.getLogger(PhoneNumberBridge.class);
	
	/**
	 * Stores a PhoneNumber into the storage medium.
	 * Considers deletion as an act of storage; thus will
	 * delete an object if the object is marked for deletion.
	 * @param myDomainObject ; The phone number to be stored.
	 */
	public static void storePhoneNumber(PhoneNumber myDomainObject) 
	{
		PhonenumberDAOImpl lDAO = new PhonenumberDAOImpl();
		int liReturnId = -1;
		
		try {
		
			if(myDomainObject.isMarkedForDeletion())
			{
				cLogger.debug("Found delete for: " + myDomainObject.toString());
				if(myDomainObject.getIdPhoneNumber() > -1)
				{
					PhonenumberKey lKey = new PhonenumberKey();
					lKey.setIdPhonenumber(new Integer(myDomainObject.getIdPhoneNumber()).longValue());
					lDAO.delete(lKey, DaoHelper.getDBConnection());
				}
				else
				{
					cLogger.info("Nothting to do for PhoneNumber:" + myDomainObject.toString() + "; it is not in the database based; decesion on no ID.");
				}
			}
			else
			{
				cLogger.debug("Update or create.");
				liReturnId = create(lDAO, myDomainObject);
			}
		}
		catch(SQLException sqlex)
		{
			cLogger.error("An exception occured while trying to perform an operation to: " + myDomainObject.toString());
			cLogger.error(sqlex.toString());
		}
		
		myDomainObject.setIdPhoneNumber(liReturnId);
	}
	
	/**
	 * Stores multiple PhoneNumber objects into the storage medium.
	 * @param myDomainObject ; An array of PhoneNumber objects.
	 */
	public static void storePhoneNumber(PhoneNumber myDomainObject[])
	{
		cLogger.debug("Entered storePhoneNumber(myPN[])");
		
		int liSize = myDomainObject.length;
		for(int i = 0; i < liSize; i++) {
			storePhoneNumber(myDomainObject[i]);
		}
		
		cLogger.info("Worked on storing " + liSize + " phone numbers.");
		
	}
	
	/**
	 * Retrieves a PhoneNumber object based on the unique
	 * id passed into it.
	 * @param myId ; A unique identifier for a PhoneNumber
	 * @return A PhoneNumber object; null if none exists or an error occurs.
	 */
	public static PhoneNumber getPhoneNumber(int myId)
	{
		PhoneNumber lNewPhoneNumber = null;
		Phonenumber lDaoObject = null;
		
		cLogger.debug("Getting a Phone Number DAO object for id: " + myId);
		
		PhonenumberDAOImpl lDAO = new PhonenumberDAOImpl();
		PhonenumberKey lKey = new PhonenumberKey();
		lKey.setIdPhonenumber((new Integer(myId)).longValue());
		
		try {
			lDaoObject = lDAO.load(lKey, DaoHelper.getDBConnection());
		}
		catch(SQLException sqlex)
		{
			cLogger.error("Error retrieving phone number with id:" + myId, sqlex);
		}
		
		lNewPhoneNumber = mapDaoToDomain(lDaoObject);
		
		return lNewPhoneNumber;
	}
	
	/**
	 * Retrieves multiple PhoneNumber objects based on a 
	 * SQL-92 based conditional clause.
	 * @return An array of PhoneNumber objects; null if an error occurs.
	 */
	public static PhoneNumber[] getPhoneNumbers(String myQuery)
	{
		PhoneNumber lDomainList[] = null;
		
		cLogger.debug("Attempting to gather multiple domain objects based" +
				" on id query: " + myQuery);
		
		ArrayList<PhoneNumber> lDomainListColl = new ArrayList<PhoneNumber>();
		
		ResultSet lRS = null;
		
		lRS = DatabaseUtil.runSelectStatement(DaoHelper.getDBConnection(),
				"SELECT ID_PHONENUMBER FROM PHONENUMBER WHERE " + myQuery);
		int lTempId =  -1;
		int i = 0;
		
		try {
			cLogger.debug("The query returned:" + lRS.getFetchSize());

			while(lRS.next()) {
				lTempId = lRS.getInt(1);
				lDomainListColl.add(getPhoneNumber((lTempId)));
			}
		}
		catch (SQLException sqlex)
		{
			cLogger.error("Exception occured while getting contacts based on"
					+ " query: " + myQuery, sqlex);
		}
		
		lDomainList = new PhoneNumber[lDomainListColl.size()];
		int count = 0;
		for(PhoneNumber c : lDomainListColl) {
			lDomainList[count] = c;
			count++;
		}
		System.out.println("Array lDomainList: \t" + lDomainList.length + "\t\tlDomainListColl: \t" + lDomainListColl.size());
	
		return lDomainList;
	}
	
	/**
	 * Performs the mappings between PhoneNumber and DAO Phonenumber objects.
	 * @param myPN ; The domain object to work on.
	 * @return A DAO object which is filled with the information in the Domain Object.
	 */
	static Phonenumber mapObject(PhoneNumber myPN)
	{
		cLogger.debug("Attempting to map a phone number.");
		cLogger.debug("PhoneNumber: " + myPN.toString());
		
		Phonenumber lPNGenerated = new Phonenumber();
		
		lPNGenerated.setIdContact(new Integer(myPN.getIdContact()).longValue());
		lPNGenerated.setIdPhonenumber(new Integer(myPN.getIdPhoneNumber()).longValue());
		lPNGenerated.setSPhonenumber(myPN.getPhoneNumber());
		lPNGenerated.setSDescription(myPN.getDescription());
		
		cLogger.debug("Generated Phonenumber mapping resulted in: " + lPNGenerated.toString());
		
		return lPNGenerated;
	}
	
	/**
	 * Maps a Dao object to the domain equivalent.
	 * @param myObject
	 * @return A Domain object; null if an error occurs.
	 */
	static PhoneNumber mapDaoToDomain(Phonenumber myObject)
	{
		cLogger.debug("Attemting to mapDaoToDomain.");
		PhoneNumber lDomain = null;
		
		if(myObject != null)
		{
			cLogger.debug("Attempting to load a phone number domain object from:" +
					myObject.toString());
			int lContactId = (new Long(myObject.getIdContact())).intValue();
			int lPhoneId = (new Long(myObject.getIdPhonenumber())).intValue();
			lDomain = new PhoneNumber(myObject.getSPhonenumber(),
					myObject.getSDescription(), lPhoneId,
					lContactId);
			
			cLogger.debug("Loaded PhoneNumber:" + lDomain.toString());
		}
		else if(cLogger.isDebugEnabled())
		{
			//if null and debug is on then log a message about the null object.
			cLogger.debug("NULL value being returned for a PhoneNumber object.");
		}
		
		return lDomain;
	}
	
	/**
	 * Create or updates a PhoneNumber object.
	 * @param myDAO ; A DAO implementation for Phonenumber.
	 * @param myDomain ; A domain object of type PhoneNumber
	 * @return The ID created or added to the database; -1 in case of an error.
	 * @throws SQLException
	 */
	static int create(PhonenumberDAO myDAO, PhoneNumber myDomain) throws SQLException
	{
		Phonenumber lDomainGenerated = mapObject(myDomain);
		String lClassName = myDomain.getClass().getCanonicalName();
		int liReturnId = -1;
		
		cLogger.debug("Attempting to create / update a " + lClassName);
		
		if(lDomainGenerated.getIdPhonenumber() > -1)
		{
			cLogger.debug("Attempt to Update Object: " + lClassName + " = " + myDomain.getIdPhoneNumber());
			myDAO.update(lDomainGenerated, DaoHelper.getDBConnection());
			
			cLogger.info("Done updating phone number.");
		}
		else
		{
			cLogger.debug("New" + lClassName + " Detected; id is -1.");
			
			//Logic here assists in testing and other special cases.
			
			if(lDomainGenerated.getIdPhonenumber() == -1)
			{
				cLogger.debug("Current id is -1; getting a new id.");
				int liNewId = DaoHelper.getNextId("Phonenumber", "ID_PHONENUMBER", DaoHelper.getDBConnection());
				cLogger.debug("Got id: " + liNewId);
				
				lDomainGenerated.setIdPhonenumber(new Integer(liNewId).longValue());
			}
			else if(cLogger.isDebugEnabled())
			{
				cLogger.debug("Id is not -1; creating a new object with the current id.");
			}
			
			myDAO.create(lDomainGenerated, DaoHelper.getDBConnection());
			
			cLogger.info("Created a new" + lClassName);
		}
		
		liReturnId = (new Long(lDomainGenerated.getIdPhonenumber())).intValue();
		myDomain.setIdPhoneNumber(liReturnId);
		cLogger.info("Id worked on " + liReturnId + " for " + lClassName);
		return liReturnId;
	}
}
